#include <iostream>
#include <string.h>
#include <cstring>
#include <memory>
#include "xmlop.h"
#include "tinyxml2.h"
#include "pugixml.hpp"
#include <sys/time.h>

using std::cout;
using std::endl;
using namespace tinyxml2;
using namespace pugi;

#define TEST_TIMES  1

#define FILE_PATH "/mnt/liuyuyan/10th_debug_5th/source/asset_discovery/asset_config.xml"
// static const char *g_config_path = "/mnt/liuyuyan/10th_debug_5th/source/asset_discovery/asset_config.xml";
static const char *g_test_config_path = "test.xml";
static const char *g_test_config_path_av = "AVConfig.xml";
static const char *g_test_config_path_asset = "asset_config.xml";
static const char *g_test_config_path_cfg = "config.xml";
static const char *g_test_config_path_vpp = "vpp_zealot.xml";
static const char *g_test_config_path_uts = "uts_config.xml";
static const char *g_test_config_path_ip_direct = "ip_direct.xml";
static const char *g_test_config_path_model = "model.xml";
#define MAC_VENDOR_FILE "/mnt/liuyuyan/11th_release/source/mac_vendor/mac_vendor.txt"


static void tiny_test_xmlop_zhushi(void)
{
    const char * s_app_file = "rulesystem.xml";
    xmlop_t xml = NULL;
    void *prev = NULL;
    void *elm = NULL;
    const char *s = NULL;
    xml = xmlop_open((char *) s_app_file);
    if (!xml) 
    {
        return ;
    }
    printf("tiny find root: %s.\n", s_app_file);
    while ((elm = xmlop_get_next(xml, prev, "root", "sysruledesc", "rules", "rule", NULL)) != NULL)
    {
        prev = elm;

        s = xmlop_get_attr(xml, elm, "ruleid");
        if (NULL == s) 
        {
            continue;
        }
        unsigned int n_rule_id = (unsigned int)atoll(s);
        printf("tiny find rule: %u.\n", n_rule_id);
        s = NULL;

        s = xmlop_get_attr(xml, elm, "cve_id");
        if (NULL == s) 
        { 
            continue;
        }
        s = NULL;

        s = xmlop_get_attr(xml, elm, "cnnvd_id");
        if (NULL == s) 
        { 
            continue;
        }
        s = NULL;

        s = xmlop_get_attr(xml, elm, "name");
        if (NULL == s) 
        { 
            continue;
        }
        s = NULL;

        s = xmlop_get_attr(xml, elm, "group");
        if (NULL == s) 
        {
            continue;
        }
        s = NULL;

        s = xmlop_get_attr(xml, elm, "module");
        if (NULL == s) 
        {
            continue;
        }
        s = NULL;
        
        s = xmlop_get_attr(xml, elm, "group_police");
        if (NULL == s) 
        {
            continue;
        }
        s = NULL;

        printf("tiny load ok: %u.\n", n_rule_id);
    }

    return ;   
}

static void tiny_parse_config_test_file(void)
{
    xmlop_t xml = NULL;
    xml = xmlop_open((char *) g_test_config_path);
    if (!xml) 
    {
        cout << "tinyxml2 failed in open xml file!" << g_test_config_path << endl;
        return;
    }
    void *cur = NULL;
    void *prev = NULL;
    const char *value = NULL;
    const char *s = NULL;
    while (1)
    {
        int return_data_found = 0;
        int mask_passwd_found = 0;
        cur = (void *)xmlop_get_next(xml, prev, "ruleFile", "globalDef", "configs", "section", NULL);
        if (cur == NULL)
        {
            cout << "ruleFile-globalDef-configs-section not found." << endl;
            return ;
        }

        s = xmlop_get_attr(xml, cur, "name");
        if (strcmp(s, "engine") == 0)
        {
            void *sub_elm;
            void *sub_prev = NULL;
            while (1)
            {
                sub_elm = xmlop_get_sub_next(xml, cur, sub_prev);
                if (sub_elm == NULL)
                {
                    cout << "get secion sub elm failed." << endl;
                    break;
                }

                s = xmlop_get_attr(xml, sub_elm, "name");
                if (strcmp(s, "get_return_data") == 0)
                {
                    return_data_found = 1;
                    value = xmlop_get_text(xml, sub_elm);
                    cout << "get_return_data value = " << value << endl;
                }
                else if (strcmp(s, "mask_passwd") == 0)
                {
                    mask_passwd_found = 1;
                    value = xmlop_get_text(xml, sub_elm);
                    cout << "get_return_data value = " << value << endl;
                }
                else if (strcmp(s, "router_config") == 0)
                {
                    value = xmlop_get_text(xml, sub_elm);
                    cout << "router_config value = " << value << endl;
                }
                sub_prev = sub_elm;

                if (return_data_found == 1 && mask_passwd_found == 1)
                    break;
            }
        }

        if (return_data_found == 1 && mask_passwd_found == 1)
            return ;

        prev = cur;
    }


    xmlop_close(xml);
}

static void tiny_test_xmlop_get(void)
{
    xmlop_t xml = NULL;
    xml = xmlop_open((char *) g_test_config_path_av);
    if (!xml) 
    {
        cout << "tinyxml2 failed in open AVConfig.xml xml file!" << g_test_config_path_av << endl;
        return;
    }
    const char *enableFileEngines_str = xmlop_get(xml, "avEngine", "engine", "file-ai", "enableFileEngines", NULL);
    if (enableFileEngines_str)
    {
        if (strcmp(enableFileEngines_str, "True") == 0)
        {
            cout << "enableFileEngines = True" << endl;
        }
        else if (strcmp(enableFileEngines_str, "False") == 0)
        {
            cout << "enableFileEngines = False" << endl;
        }
        else
        {
            cout << "enableFileEngines = " << enableFileEngines_str << endl;
        }
    }
    xmlop_close(xml);
}

static void tiny_test_xmlop_get_elm(void)
{
    xmlop_t xml = NULL;
    xml = xmlop_open((char *) g_test_config_path_asset);
    if (!xml) 
    {
        cout << "tinyxml2 failed in open asset_config.xml xml file!" << g_test_config_path_asset << endl;
        return;
    }

    void *elm = NULL;
    const char *s = NULL;
    elm = xmlop_get_elm(xml, "root", "asset_config", NULL);
    if (elm == NULL)
    {
        cout << "node asset_config not found" << endl;
        return;
    }
    cout << "node asset_config = " << elm << endl;

    s = xmlop_get_attr(xml, elm, "enable");
    if (s && strcmp(s, "true") == 0)
    {
        cout << "enable = true" << endl;
    }
    xmlop_close(xml);
}

static void tiny_test_xmlop_get_next(void)
{
    xmlop_t xml = NULL;
    xml = xmlop_open((char *) g_test_config_path_cfg);
    if (!xml) 
    {
        cout << "tinyxml2 failed in open config.xml xml file!" << g_test_config_path_cfg << endl;
        return;
    }

    void *prev;
    void *elm;
    const char *s;
    prev = NULL;
    while (1)
    {
        int found = 0;
        elm = (void *) xmlop_get_next(xml, prev, "ruleFile", "globalDef", "configs", "section", NULL);
        cout << "elm = " << elm << endl;
        if (elm == NULL)
            break;
        
        s = xmlop_get_attr(xml, elm, "name");
        cout << "s = " << s << endl;
        if (!s) {
            cout << "xmlop_get_attr returned NULL for 'name' attribute." << endl;
            xmlop_close(xml);
            return ;
        }
        
        if (strcmp(s, "engine") == 0)
        {
            void *sub_elm;
            void *sub_prev = NULL;
#if 1
            while (1)
            {
                sub_elm = xmlop_get_sub_next(xml, elm, sub_prev);
                if (sub_elm == NULL)
                    break;
                
                s = xmlop_get_attr(xml, sub_elm, "name");
                if (!s) {
                    cout << "xmlop_get_attr returned NULL for 'name' attribute in sub-element.\n";
                    xmlop_close(xml);
                    return;
                }
                
                if (strcmp(s, "sarbanes_weak_passwd_options") == 0)
                {
                    cout << "found sarbanes_weak_passwd_options" << endl;
                    found = 1;
                    s = xmlop_get_text(xml, sub_elm);
                    if (!s) {
                        cout << "xmlop_get_text returned NULL for sarbanes_weak_passwd_options.\n";
                        xmlop_close(xml);
                        return ;
                    }
                    break;
                }
                
                if (strcmp(s, "mask_passwd") == 0)
                {
                    cout << "found mask_passwd" << endl;
                    found = 1;
                    s = xmlop_get_text(xml, sub_elm);
                    if (!s) {
                        cout << "xmlop_get_text returned NULL for mask_passwd.\n";
                        xmlop_close(xml);
                        return;
                    }
                    break;
                }
                sub_prev = sub_elm;
            } 
#endif       
        }

        if (found == 1)
            break;

        prev = elm;
    }    
    xmlop_close(xml);
}

static void tiny_test_xmlop_get_text(void)
{
    xmlop_t xml = NULL;
    xml = xmlop_open((char *) g_test_config_path_vpp);
    if (!xml) 
    {
        cout << "tinyxml2 failed in open vpp_zealot.xml xml file!" << g_test_config_path_vpp << endl;
        return;
    }

    void *prev = NULL;
    void *cur  = NULL;
    int v;
    const char *t;
    while (1)
    {
        cur = xmlop_get_next(xml, prev, "root", "zealot", "function-ids", "function-id", NULL);
        cout << "cur = " << cur << endl;
        if (cur == NULL)
            break;
        t = xmlop_get_text(xml, cur);
        v = atoi(t);
        cout << "t = " << t << endl;
        cout << "v = " << v << endl;

        prev = cur;
    }
    xmlop_close(xml);
}

static void tiny_test_xmlop_get_sub_elm(void)
{
    xmlop_t xml = NULL;
    void *ele = NULL;
    void *root_ele = NULL;
    const char *attr = NULL;
    xml = xmlop_open((char *) g_test_config_path_uts);
    if (!xml) 
    {
        cout << "tinyxml2 failed in open uts_config xml file!" << g_test_config_path_uts << endl;
        return;
    }

    root_ele = xmlop_get_elm(xml, "root", NULL);
    if (!root_ele) {
        cout << "No root element found in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }

    ele = xmlop_get_sub_elm(xml, root_ele, "phishing_email");
    if (!ele) {
        cout << "No phishing_email element found in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }

    attr = xmlop_get_attr(xml, ele, "enabled");
    if (attr == NULL) {
        cout << "phishing_email element no enabled attr in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }
    if (strcasecmp(attr, "true") == 0) {
        cout << "detect_enabled true " << endl;
    }
    else
        cout << "detect_enabled is not true " << attr << endl;

XML_PARAM_PARSE_FAIL:
    xmlop_close(xml);
    return ;
}

static void tiny_test_xmlop_get_sub_next(void)
{
    xmlop_t xml = NULL;
    const char *value = NULL;
    // 打开XML
    xmlop_t x = xmlop_open(g_test_config_path_ip_direct);
    if (x == NULL) {
        cout << "tinyxml2 xmlop_open failed " << g_test_config_path_ip_direct<< endl;
        return ;  // 无法打开XML文件，直接返回空的XML数据结构体
    }

    else
        cout << "tinyxml2 xmlop_open success " << g_test_config_path_ip_direct<< endl;

    // 获取根
    void *root = xmlop_get_elm(x, "root", NULL);
    if (root == NULL) {
        xmlop_close(x);
        return ;  //无法获取根元素，直接返回空的XML数据结构体
    }

    // 获取network_object
    void *networkObject = xmlop_get_sub_elm(x, root, "network_object");
    if (networkObject == NULL) {
        xmlop_close(x);
        return ;  // 无法获取"network_object" 元素，直接返回空的XML数据结构体
    }

    // // 获取ippools
    // void *ippools = xmlop_get_sub_elm(x, networkObject, "ippools");
    // cout << "networkObject " << networkObject << " ippools " << ippools << endl;
    // if (ippools != NULL) {
    //     // 获取第一个ippool
    //     void *ippool = xmlop_get_sub_next(x, ippools, NULL);
    //     cout << "ippool " << ippool << endl;
    //     while (ippool != NULL) {
    //         ippool = xmlop_get_sub_next(x, ippools, ippool);
    //         cout << "ippool=" << ippool << endl;
    //         value = xmlop_get_text(x, ippool);
    //         cout << "value=" << value;
    //     }
    //     cout << "ippools " << ippools << endl;
    // }

    // 获取networks
    cout << "获取networks " << endl;
    void *networks = xmlop_get_sub_elm(x, networkObject, "networks");
    cout << "networkObject " << networkObject << " networks " << networks << endl;
    if (networks != NULL) {
        // 获取第一个network
        void *network = xmlop_get_sub_next(x, networks, NULL);
        printf("network=%p.\n", network);
        while (network != NULL) {
            // 解析network
            network = xmlop_get_sub_next(x, networks, network);
            printf("network=%p.\n", network);
        }
        printf("networks2=%p.\n", networks);
    }

    // 关闭XML文档
    cout << "tinyxml2 xmlop_close" << endl;
    xmlop_close(x);
    // 返回解析结果
    return ;
}

// 测试开关文件
static void pugi_test_open_close(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path);
    if (!xml) 
    {
        cout << "pugixml failed in open xml file!" << g_test_config_path << endl;
        return;
    }
    pugi_xmlop_close(xml);
}

// 测试获取节点
static void pugi_test_xmlop_get_elm(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_asset);
    if (!xml) 
    {
        cout << "pugixml failed in open asset_config.xml xml file!" << g_test_config_path_asset << endl;
        return;
    }

    void *elm = NULL;
    const char *s = NULL;
    elm = pugi_xmlop_get_elm(xml, "root", "asset_config", NULL);
    if (elm == NULL)
    {
        cout << "node asset_config not found" << endl;
        return;
    }
    cout << "node asset_config = " << elm << endl;

    // s = pugi_xmlop_get_attr(xml, elm, "enable");
    // if (s && strcmp(s, "true") == 0)
    // {
    //     cout << "enable = true" << endl;
    // }
    pugi_xmlop_close(xml);
}

// 测试获取节点的配置值
static void pugi_test_xmlop_get(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_av);
    if (!xml) 
    {
        cout << "tinyxml2 failed in open AVConfig.xml xml file!" << g_test_config_path_av << endl;
        return;
    }
    const char *enableFileEngines_str = pugi_xmlop_get(xml, "avEngine", "engine", "file-ai", "enableFileEngines", NULL);
    if (enableFileEngines_str)
    {
        if (strcmp(enableFileEngines_str, "True") == 0)
        {
            cout << "enableFileEngines = True" << endl;
        }
        else if (strcmp(enableFileEngines_str, "False") == 0)
        {
            cout << "enableFileEngines = False" << endl;
        }
        else
        {
            cout << "enableFileEngines = " << enableFileEngines_str << endl;
        }
    }
    pugi_xmlop_close(xml);
}

// 测试获取xml的配置项，用于多个配置路径相同的情况
static void pugi_test_xmlop_get_next(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_cfg);
    if (!xml) 
    {
        cout << "pugi_xml failed in open config.xml xml file!" << g_test_config_path_cfg << endl;
        return;
    }

    void *prev;
    void *elm;
    const char *s;
    prev = NULL;
    while (1)
    {
        int count = 0;
        elm = (void *) pugi_xmlop_get_next(xml, prev, "ruleFile", "globalDef", "configs", "section", NULL);
        cout << "elm = " << elm << endl;
        if (elm == NULL)
            break;
        count++;
        if (count == 10)
        {
            cout << "elm = " << elm << endl;
            cout << "count = " << count << endl;
            break;
        }

        prev = elm;
    }    
    pugi_xmlop_close(xml);
}

// 测试获取xml的配置项，用于多个配置路径相同的情况
// 测试循环退出
static void pugi_test_xmlop_get_next_while(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_cfg);
    if (!xml) 
    {
        cout << "pugi_xml failed in open config.xml xml file!" << g_test_config_path_cfg << endl;
        return;
    }

    void *prev;
    void *elm;
    const char *s;
    prev = NULL;
    while (1)
    {
        int found = 0;
        elm = (void *) pugi_xmlop_get_next(xml, prev, "ruleFile", "globalDef", "configs", "section", NULL);
        cout << "elm = " << elm << endl;
        if (elm == NULL)
            break;
        
        s = pugi_xmlop_get_attr(xml, elm, "name");
        cout << "s = " << s << endl;
        if (!s) {
            cout << "xmlop_get_attr returned NULL for 'name' attribute." << endl;
            pugi_xmlop_close(xml);
            return ;
        }
        
        if (strcmp(s, "engine") == 0)
        {
            void *sub_elm;
            void *sub_prev = NULL;
#if 1
            while (1)
            {
                sub_elm = pugi_xmlop_get_sub_next(xml, elm, sub_prev);
                if (sub_elm == NULL)
                    break;
                
                s = pugi_xmlop_get_attr(xml, sub_elm, "name");
                if (!s) {
                    cout << "xmlop_get_attr returned NULL for 'name' attribute in sub-element.\n";
                    pugi_xmlop_close(xml);
                    return;
                }
                
                if (strcmp(s, "sarbanes_weak_passwd_options") == 0)
                {
                    cout << "found sarbanes_weak_passwd_options" << endl;
                    found = 1;
                    s = pugi_xmlop_get_text(xml, sub_elm);
                    if (!s) {
                        cout << "xmlop_get_text returned NULL for sarbanes_weak_passwd_options.\n";
                        pugi_xmlop_close(xml);
                        return ;
                    }
                    break;
                }
                
                if (strcmp(s, "mask_passwd") == 0)
                {
                    cout << "found mask_passwd" << endl;
                    found = 1;
                    s = pugi_xmlop_get_text(xml, sub_elm);
                    if (!s) {
                        cout << "xmlop_get_text returned NULL for mask_passwd.\n";
                        pugi_xmlop_close(xml);
                        return;
                    }
                    break;
                }
                sub_prev = sub_elm;
            }
#endif
        }

        if (found == 1)
            break;

        prev = elm;
    }    
    pugi_xmlop_close(xml);
}

// 测试获取配置项关联的字符串。
static void pugi_test_xmlop_get_text(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_vpp);
    if (!xml) 
    {
        cout << "pugixml failed in open vpp_zealot.xml xml file!" << g_test_config_path_vpp << endl;
        return;
    }

    void *prev = NULL;
    void *cur  = NULL;
    int v;
    const char *t;
    while (1)
    {
        cur = pugi_xmlop_get_next(xml, prev, "root", "zealot", "function-ids", "function-id", NULL);
        cout << "cur = " << cur << endl;
        if (cur == NULL)
            break;
        t = pugi_xmlop_get_text(xml, cur);
        v = atoi(t);
        cout << "t = " << t << endl;
        cout << "v = " << v << endl;

        prev = cur;

    }
    pugi_xmlop_close(xml);
}

// 测试获取配置项关联的属性值
static void pugi_test_xmlop_get_attr(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_asset);
    if (!xml) 
    {
        cout << "pugixml failed in open asset_config.xml xml file!" << g_test_config_path_asset << endl;
        return;
    }

    void *elm = NULL;
    const char *s = NULL;
    elm = pugi_xmlop_get_elm(xml, "root", "asset_config", NULL);
    if (elm == NULL)
    {
        cout << "node asset_config not found" << endl;
        return;
    }
    cout << "node asset_config = " << elm << endl;

    s = pugi_xmlop_get_attr(xml, elm, "enable");
    if (s && strcmp(s, "true") == 0)
    {
        cout << "enable = true" << endl;
    }

    elm = pugi_xmlop_get_elm(xml, "root", "asset_config", "ip_range", NULL);
    if (elm == NULL)
    {
        cout << "node ip_range not found" << endl;
        return;
    }
    cout << "node ip_range = " << elm << endl;

    s = pugi_xmlop_get_attr(xml, elm, "end");
    if (s)
    {
        cout << "end = " << s << endl;
    }

    s = pugi_xmlop_get_attr(xml, elm, "id");
    if (s)
    {
        cout << "id = " << s << endl;
    }

    s = pugi_xmlop_get_attr(xml, elm, "group_name");
    if (s)
    {
        cout << "group_name = " << s << endl;
    }

    pugi_xmlop_close(xml);
}

// 测试获取xml 某个elm的子elm，根据子节点名称选择
static void pugi_test_xmlop_get_sub_elm(void)
{
    pugi_xmlop_t xml = NULL;
    void *ele = NULL;
    void *root_ele = NULL;
    const char *attr = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_uts);
    if (!xml) 
    {
        cout << "pugixml failed in open uts_config xml file!" << g_test_config_path_uts << endl;
        return;
    }

    root_ele = pugi_xmlop_get_elm(xml, "root", NULL);
    if (!root_ele) {
        cout << "No root element found in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }

    cout << "++++++++++++++++  phishing_email  start ++++++++++++++++++++++" << endl;
    ele = pugi_xmlop_get_sub_elm(xml, root_ele, "phishing_email");
    if (!ele) {
        cout << "No phishing_email element found in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }

    attr = pugi_xmlop_get_attr(xml, ele, "enabled");
    if (attr == NULL) {
        cout << "phishing_email element no enabled attr in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }
    if (strcasecmp(attr, "true") == 0) {
        cout << "detect_enabled true " << endl;
    }
    else
        cout << "detect_enabled is not true " << attr << endl;
    cout << "++++++++++++++++  phishing_email  end ++++++++++++++++++++++" << endl;


    cout << "++++++++++++++++  ackflood  start ++++++++++++++++++++++" << endl;
    ele = pugi_xmlop_get_sub_elm(xml, root_ele, "ackflood");
    if (!ele) {
        cout << "No ackflood element found in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }

    attr = pugi_xmlop_get_attr(xml, ele, "enabled");
    if (attr == NULL) {
        cout << "ackflood element no enabled attr in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }
    if (strcasecmp(attr, "true") == 0) {
        cout << "ackflood_enabled true " << endl;
    }
    else
        cout << "ackflood_enabled is not true " << attr << endl;

    cout << "++++++++++++++++  ackflood->cps_ipv4_num  start ++++++++++++++++++++++" << endl;
    ele = pugi_xmlop_get_sub_elm(xml, ele, "cps_ipv4_num");
    if (!ele) {
        cout << "No ackflood->cps_ipv4_num element found in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }

    attr = pugi_xmlop_get_attr(xml, ele, "value");
    if (attr == NULL) {
        cout << "ackflood->cps_ipv4_num element no enabled attr in XML file: " << g_test_config_path_uts << endl;
        goto XML_PARAM_PARSE_FAIL;
    }
    if (strcasecmp(attr, "100000") == 0) {
        cout << "ackflood->cps_ipv4_num = " << attr << endl;
    }
    else
        cout << "ackflood->cps_ipv4_num is not true " << attr << endl;
    cout << "++++++++++++++++  ackflood->cps_ipv4_num  end ++++++++++++++++++++++" << endl;
    cout << "++++++++++++++++  ackflood  end ++++++++++++++++++++++" << endl;

XML_PARAM_PARSE_FAIL:
    pugi_xmlop_close(xml);
    return ;
}

// 测试获取xml 某个elm的子elm
static void pugi_test_xmlop_get_sub_next(void)
{
    pugi_xmlop_t xml = NULL;
    const char *value = NULL;
    // 打开XML
    pugi_xmlop_t x = pugi_xmlop_open(g_test_config_path_ip_direct);
    if (x == NULL) {
        cout << "pugi xmlop_open failed " << g_test_config_path_ip_direct<< endl;
        return ;  // 无法打开XML文件，直接返回空的XML数据结构体
    }

    else
        cout << "pugi_xmlop_open success " << g_test_config_path_ip_direct<< endl;

    // 获取根
    void *root = pugi_xmlop_get_elm(x, "root", NULL);
    if (root == NULL) {
        pugi_xmlop_close(x);
        return ;  //无法获取根元素，直接返回空的XML数据结构体
    }

    // 获取network_object
    void *networkObject = pugi_xmlop_get_sub_elm(x, root, "network_object");
    if (networkObject == NULL) {
        pugi_xmlop_close(x);
        return ;  // 无法获取"network_object" 元素，直接返回空的XML数据结构体
    }

    // 获取ippools
    cout << "获取ippools " << endl;
    void *ippools = pugi_xmlop_get_sub_elm(x, networkObject, "ippools");
    if (ippools != NULL) {
        // 获取第一个ippool
        void *ippool = pugi_xmlop_get_sub_next(x, ippools, NULL);
        cout << "ippool " << ippool << endl;
        while (ippool != NULL) {
            ippool = pugi_xmlop_get_sub_next(x, ippools, ippool);
            cout << "ippool=" << ippool << endl;
        }
        cout << "ippools " << ippools << endl;
    }

    cout << "获取networks " << endl;
    // 获取networks
    cout << "networkObject " << networkObject << " ippools " << ippools << endl;
    void *networks = pugi_xmlop_get_sub_elm(x, networkObject, "networks");
    cout << "networkObject " << networkObject << " networks " << networks << endl;
    if (networks != NULL) {
        // 获取第一个network
        void *network = pugi_xmlop_get_sub_next(x, networks, NULL);
        printf("network=%p.\n", network);
        while (network != NULL) {
            // 解析network
            network = pugi_xmlop_get_sub_next(x, networks, network);
            printf("子节点 network=%p.\n", network);
        }
        printf("networks2=%p.\n", networks);
    }

    // 关闭XML文档
    cout << "pugi_xmlop_close" << endl;
    pugi_xmlop_close(x);
    // 返回解析结果
    return ;
}

// 测试xpath接口
static void pugi_test_xmlop_xpath(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_cfg);
    if (!xml) 
    {
        cout << "pugixml failed in open xml file!" << g_test_config_path_cfg << endl;
        return;
    }
    
    void *elm = NULL;
    const char *s = NULL;

    char *path = "/ruleFile/globalDef/configs/section/config[@name='router_config']";
    s = pugi_xpath_get_text(xml,path);
    cout << "s = " << s << endl;

    path = "/ruleFile/globalDef/configs/section/config[@input_type_verify='bool' and @name='router_mode']";
    s = pugi_xpath_get_text(xml,path);
    cout << "s = " << s << endl;

    #define NODE_NUM 480
    uint32_t ret = 0;
    char *xml_str[NODE_NUM] = {NULL,NULL};
    path = "//ruleFile/flieInfo/test";
    ret = xmlop_xpath_get_text_batch(xml, path, xml_str, NODE_NUM);
    if (!ret)
    {
        cout << "node count is 0 or get text failed" << endl;
    }
    else
    {
        cout << "xmlop_xpath_get_text_batch count is " << ret << endl;
        for (int i = 0; i < ret; i++)
        {
            if (xml_str[i])
            {
                cout << "xml_str[" << i << "] = " << xml_str[i] << endl;
            }
        }
    }

    memset(xml_str, 0, sizeof(xml_str));

    path = "//config";
    ret = xmlop_xpath_get_text_batch(xml, path, xml_str, NODE_NUM);
    if (!ret)
    {
        cout << "node count is 0 or get text failed" << endl;
    }
    else
    {
        cout << "xmlop_xpath_get_text_batch count is " << ret << endl;
        for (int i = 0; i < ret; i++)
        {
            if (xml_str[i])
            {
                cout << "xml_str[" << i << "] = " << xml_str[i] << endl;
            }
        }
    }

    memset(xml_str, 0, sizeof(xml_str));

    path = "//port";
    ret = xmlop_xpath_get_text_batch(xml, path, xml_str, NODE_NUM);
    if (!ret)
    {
        cout << "node count is 0 or get text failed" << endl;
    }
    else
    {
        cout << "xmlop_xpath_get_text_batch count is " << ret << endl;
        for (int i = 0; i < ret; i++)
        {
            if (xml_str[i])
            {
                cout << "xml_str[" << i << "] = " << xml_str[i] << endl;
            }
        }
    }

    memset(xml_str, 0, sizeof(xml_str));

    pugi_xmlop_close(xml);
}


static void pugi_test_xmlop_xpath_get_attr_sets(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_uts);
    if (!xml) 
    {
        cout << "pugixml failed in open xml file!" << g_test_config_path_cfg << endl;
        return;
    }
    

    #define NODE_NUM 480
    uint32_t ret = 0;
    char *xml_str[NODE_NUM] = {NULL,NULL};
    const char *path = "//protocol[@name='API']";
    const char *attr = "id";
    ret = xmlop_xpath_get_attr_batch(xml, path, attr, xml_str, NODE_NUM);
    if (!ret)
    {
        cout << "node count is 0 or get text failed" << endl;
    }
    else
    {
        cout << "xmlop_xpath_get_text_batch count is " << ret << endl;
        for (int i = 0; i < ret; i++)
        {
            if (xml_str[i])
            {
                cout << "xml_str[" << i << "] = " << xml_str[i] << endl;
            }
        }
    }

    memset(xml_str, 0, sizeof(xml_str));

    path = "//protocol";
    attr = "id";
    ret = xmlop_xpath_get_attr_batch(xml, path, attr, xml_str, NODE_NUM);
    if (!ret)
    {
        cout << "node count is 0 or get text failed" << endl;
    }
    else
    {
        cout << "xmlop_xpath_get_text_batch count is " << ret << endl;
        for (int i = 0; i < ret; i++)
        {
            if (xml_str[i])
            {
                cout << "xml_str[" << i << "] = " << xml_str[i] << endl;
            }
        }
    }

    memset(xml_str, 0, sizeof(xml_str));


    pugi_xmlop_close(xml);
}


static void pugi_test_xmlop_xmlnodedelet(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_asset);
    if (!xml) 
    {
        cout << "pugixml failed in open asset_config.xml xml file!" << g_test_config_path_asset << endl;
        return;
    }

    {
        void *elm = NULL;
        const char *s = NULL;
        elm = pugi_xmlop_get_elm(xml, "root", "asset_config", NULL);
        if (elm == NULL)
        {
            cout << "node asset_config not found" << endl;
            return;
        }
        cout << "node asset_config = " << elm << endl;
        
    }

    pugi_xmlop_close(xml);
}

static void tiny_test_xmlop_parse_model_xml(void)
{
    xmlop_t xml = NULL;
    xml =xmlop_open((char *) g_test_config_path_model);
    if (!xml) 
    {
        cout << "tinyxml failed in open model.xml file!" << g_test_config_path_model << endl;
        return;
    }

    {
        uint32_t cpu_num = 0;
        void *ele = xmlop_get_elm(xml, "root", "cpus", NULL);
        void *sub_ele = NULL;
        int max_cpu_num = 256;
        sub_ele = xmlop_get_sub_next(xml, ele, sub_ele);
        while (sub_ele)
        {
            const char *type_attr = xmlop_get_attr(xml, sub_ele, "type");
            if (type_attr)
            {
                cout << "type_attr = " << type_attr << endl;
                const char *cpu_attr = xmlop_get_attr(xml, sub_ele, "id");
                if (cpu_attr) {
                    cout << "cpu_attr = " << cpu_attr << endl;
                }
    
                const char *numa_attr = xmlop_get_attr(xml, sub_ele, "node");
                if (numa_attr) {
                    cout << "numa_attr = " << numa_attr << endl;
                }
                const char *ratio_attr = xmlop_get_attr(xml, sub_ele, "ratio");
                if (ratio_attr) {
                    cout << "ratio_attr = " << ratio_attr << endl;
                }
                cpu_num++;
                if (cpu_num >= max_cpu_num) {
                    xmlop_close(xml);
                    return;
                }

            }
            else
                cout << NULL << endl;

            sub_ele = xmlop_get_sub_next(xml, ele, sub_ele);
        }
        
    }

    xmlop_close(xml);
}

// 解析model.xml server 起不来
static void pugi_test_xmlop_parse_model_xml(void)
{
    pugi_xmlop_t xml = NULL;
    xml = pugi_xmlop_open((char *) g_test_config_path_model);
    if (!xml) 
    {
        cout << "pugixml failed in open model.xml file!" << g_test_config_path_model << endl;
        return;
    }

    {
        uint32_t cpu_num = 0;
        void *ele = pugi_xmlop_get_elm(xml, "root", "cpus", NULL);
        void *sub_ele = NULL;
        int max_cpu_num = 256;
        sub_ele = pugi_xmlop_get_sub_next(xml, ele, sub_ele);
        while (sub_ele)
        {
            const char *type_attr = pugi_xmlop_get_attr(xml, sub_ele, "type");
            if (type_attr)
            {
                cout << "type_attr = " << type_attr << endl;
                const char *cpu_attr = pugi_xmlop_get_attr(xml, sub_ele, "id");
                if (cpu_attr) {
                    cout << "cpu_attr = " << cpu_attr << endl;
                }
    
                const char *numa_attr = pugi_xmlop_get_attr(xml, sub_ele, "node");
                if (numa_attr) {
                    cout << "numa_attr = " << numa_attr << endl;
                }
                const char *ratio_attr = pugi_xmlop_get_attr(xml, sub_ele, "ratio");
                if (ratio_attr) {
                    cout << "ratio_attr = " << ratio_attr << endl;
                }
                cpu_num++;
                if (cpu_num >= max_cpu_num) {
                    pugi_xmlop_close(xml);
                    return;
                }

            }
            else
                cout << NULL << endl;

            sub_ele = pugi_xmlop_get_sub_next(xml, ele, sub_ele);
        }
        
    }

    pugi_xmlop_close(xml);
}


// 测试带有注释的xml解析
static void pugi_test_xmlop_zhushi(void)
{
    const char * s_app_file = "rulesystem.xml";
    pugi_xmlop_t xml = NULL;
    void *prev = NULL;
    void *elm = NULL;
    const char *s = NULL;
    xml = pugi_xmlop_open((char *) s_app_file);
    if (!xml) 
    {
        return ;
    }
    printf("pugi_find root: %s.\n", s_app_file);
    while ((elm = pugi_xmlop_get_next(xml, prev, "root", "sysruledesc", "rules", "rule", NULL)) != NULL)
    {
        prev = elm;

        s = pugi_xmlop_get_attr(xml, elm, "ruleid");
        if (NULL == s) 
        {
            continue;
        }
        unsigned int n_rule_id = (unsigned int)atoll(s);
        printf("pugi_find rule: %u.\n", n_rule_id);
        s = NULL;

        s = pugi_xmlop_get_attr(xml, elm, "cve_id");
        if (NULL == s) 
        { 
            continue;
        }
        s = NULL;

        s = pugi_xmlop_get_attr(xml, elm, "cnnvd_id");
        if (NULL == s) 
        { 
            continue;
        }
        s = NULL;

        s = pugi_xmlop_get_attr(xml, elm, "name");
        if (NULL == s) 
        { 
            continue;
        }
        s = NULL;

        s = pugi_xmlop_get_attr(xml, elm, "group");
        if (NULL == s) 
        {
            continue;
        }
        s = NULL;

        s = pugi_xmlop_get_attr(xml, elm, "module");
        if (NULL == s) 
        {
            continue;
        }
        s = NULL;
        
        s = pugi_xmlop_get_attr(xml, elm, "group_police");
        if (NULL == s) 
        {
            continue;
        }
        s = NULL;

        printf("pugi_load ok: %u.\n", n_rule_id);
    }

    return ;   
}

int main()
{
    double tiny_time = 0;
    double pugixml_time = 0;
    {
        timeval starttime, endtime;
        double timeuse = 0.;
        double timeAverage = 0.;
        for( int i = 0; i < TEST_TIMES; ++i )
        {
            gettimeofday( &starttime, 0 );
            // tiny_parse_config_test_file();
            // tiny_test_xmlop_get();
            // tiny_test_xmlop_get_elm();
            // tiny_test_xmlop_get_next();
            // tiny_test_xmlop_get_text();
            // tiny_test_xmlop_get_sub_elm();
            // tiny_test_xmlop_get_sub_next();
            tiny_test_xmlop_zhushi();
            gettimeofday( &endtime, 0 );
            timeuse = 1000000. * (endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec;
            timeuse *= 0.001 ;
            cout << " tinyxml2 reading files costs : " << timeuse << "ms" << endl;
            timeAverage += timeuse;
        }
        timeAverage /= TEST_TIMES;
        tiny_time = timeAverage;
        cout << " \n** The end *******************\n   tinyxml2 the average costs = " << timeAverage << "ms" << endl;
    }

    {
        timeval starttime, endtime;
        double timeuse = 0.;
        double timeAverage = 0.;
        for( int i = 0; i < TEST_TIMES; ++i )
        {
            gettimeofday( &starttime, 0 );
            // pugi_test_open_close();
            // pugi_test_xmlop_get();
            // pugi_test_xmlop_get_elm();
            // pugi_test_xmlop_get_next();
            // pugi_test_xmlop_get_text();
            // pugi_test_xmlop_get_attr();
            // pugi_test_xmlop_get_sub_elm();
            // pugi_test_xmlop_get_sub_next();
            // pugi_test_xmlop_get_next_while();
            // pugi_test_xmlop_xpath();
            // pugi_test_xmlop_xpath_get_attr_sets();
            // pugi_test_xmlop_xmlnodedelet();
            // pugi_test_xmlop_parse_model_xml();
            pugi_test_xmlop_zhushi();
            gettimeofday( &endtime, 0 );

            timeuse = 1000000. * (endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec;
            timeuse *= 0.001 ;
            cout << " pugixml reading files costs : " << timeuse << "ms" << endl;
            timeAverage += timeuse;
        }
        timeAverage /= TEST_TIMES;
        pugixml_time = timeAverage;
        cout << " \n** The end *******************\n   pugixml the average costs = " << timeAverage << "ms" << endl;
    }
    cout << " \n** The end *******************\n   tinyxml2 the average costs = " << tiny_time << "ms" << endl;
    cout << " \n** The end *******************\n   pugixml the average costs = " << pugixml_time << "ms" << endl;
    return 0;
}
